#ifndef __BUOLA_GL_CSHADER_H__
#define __BUOLA_GL_CSHADER_H__

#include <buola/gl.h>

namespace buola { namespace gl {

class CShader
{
public:
    enum EType
    {
        VERTEX=GL_VERTEX_SHADER,
        FRAGMENT=GL_FRAGMENT_SHADER,
        GEOMETRY=GL_GEOMETRY_SHADER
    };

    CShader()
        :   mID(0)
    {}

    CShader(EType pType)
        :   mID(0)
    {
        Create(pType);
    }

    CShader(EType pType,const std::string &pSource)
        :   mID(0)
    {
        Create(pType,pSource);
    }

    CShader(EType pType,const char *pSource)
        :   mID(0)
    {
        Create(pType,pSource);
    }

    ~CShader()
    {
        if(mID)
            Delete();
    }

    void Create(EType pType)
    {
        if(mID) Delete();
        mID=glCreateShader((GLenum)pType);
    }

    void Create(EType pType,const std::string &pSource)
    {
        if(mID) Delete();
        mID=glCreateShader((GLenum)pType);
        SetSource(pSource);
    }

    void Create(EType pType,const char *pSource)
    {
        if(mID) Delete();
        mID=glCreateShader((GLenum)pType);
        SetSource(pSource);
    }

    void SetSource(const std::string &pSource)
    {
        const char *lSource=pSource.data();
        GLint lLength=pSource.size();
        glShaderSource(mID,1,&lSource,&lLength);
    }

    void SetSource(const char *pSource)
    {
        glShaderSource(mID,1,&pSource,nullptr);
    }

    void Delete()
    {
        glDeleteShader(mID);
        mID=0;
    }

    void Compile(bool pCheck=true)
    {
        glCompileShader(mID);

        if(pCheck)
        {
            GLint lStatus;
            glGetShaderiv(mID,GL_COMPILE_STATUS,&lStatus);
            if(!lStatus)
            {
                GLint lLogLen=0;

                glGetShaderiv(mID,GL_INFO_LOG_LENGTH,&lLogLen);

                char lData[lLogLen];
                GLint lRead=0;
                glGetShaderInfoLog(mID,lLogLen,&lRead,lData);

                throw XInternal(std::string("error compiling shader: ")+lData);
            }
        }
    }

    GLuint GetID() const     {   return mID; }

    explicit operator bool()
    {
        return mID!=0;
    }

private:
    GLuint mID;
};

/*namespace gl*/ } /*namespace buola*/ }

#endif
